package com.iflytek.sbd.demo.jihe.map;

import java.util.HashMap;

/**
 * @program: sbd
 * @description:
 * @author: 陈英俊
 * @create: 2022-01-12 15:23
 */
public class HashMapDemo {

    public static void main(String[] args) {

        // 无参构造方法底层仅仅是设置了加载系数=0.75
        //     HashMap<String, String> map1 = new HashMap<>();
        // 初始容量构造方法,设置默认加载系数,初始容量设置为靠近的2的次幂
        /**
         * HashMap的几个构造方法都是指定初始值和负载因子的大小.
         * 如果我们不指定参数,初始值默认是16,加载因子默认是0.75;
         * HashMap的大小只能是2的次幂,你传10,变成16,你传7,变成8,这都是里面tableSizeFor处理的
         * 每次我们put的时候,都会经过一个方法hash(key)算出key的哈希值,因为里面使用位运算替代取模,这样可以更加高效的运算
         * 这也是为啥HashMap的大小为啥需要2的次幂,因为2的次幂才能合理高效使用位运算代替取模;
         * 负载因子的大小,决定着哈希表的扩容和哈希冲突;
         * 假如我现在HashMap的大小是16,负载因子是0.75.这就表示数组最多只能存放 16*0.75=12 个元素,一旦数据长度超过12,哈希表需要进行扩容
         * 由于一般HashMap的大小都是2的次幂,所以扩容的时候都是默认扩容为原来的2倍
         * 这里面负载因子决定扩容,我们可以把负载因子调大,来减少扩容的次数,这样是可以的,但是是不推荐的,因为哈希冲突的概念就会变高,查找也会更加费时
         * 这里面的hash(key)对键的操作是: 先取键的哈希值,然后与高16位做异或运算,这样也是为了增加随机性,减少哈希冲突
         * 我们在put的时候,首先会根据hash(key)得到key的哈希值,然后计算key的index,没有碰到直接插入数组,如果碰到了,根据当前的数据结构是链表还是红黑树进行插入
         * 假设key是相同的,相同的就替换,最后判断哈希表是否达到了扩容阈值(当前哈希表大小*加载因子).达到了进行扩容.
         * get的时候,也是对key进行哈希运算,然后计算index的位置,判断是否有哈希冲突,没有冲突直接返回,有冲突,根据当前数据结构是链表还是红黑树取出数据
         *
         * 当数组的大小并且链表的大小大于8的时候,才会将链表改为红黑树,当红黑树大小为6时,退化为链表
         *
         */
        HashMap<String, String> map2 = new HashMap<>(13);
        map2.put("key", "value");
        map2.put("1","2");
        System.out.println(map2.get("key"));
    }
}
